﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Web;
using System.IO;
using log4net;

namespace Entangle
{
    class SynchService
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(SynchService));

        string uri;

        public SynchService(string pServerURI)
        {
            uri = pServerURI;
        }

        public void Synch2(string pSynchKey)
        {
            ServerConnector sc = new ServerConnector(uri);
            string result = sc.Synch(pSynchKey, Cryptography.Instance.GetPublicKeyXML());

            string[] rArray = result.Split(':');
            if(rArray.Length < 2)
                rArray = new string[] {rArray[0], String.Empty}; // Safeguard

            string type = rArray[0];
            int userId;
            log.Debug("type=" + type);
            switch(type)
            {
                case  MessageType.ENTANGLED:
                    log.Info("Entangled on server. Parsing returned user id");
                    userId = int.Parse(rArray[1]);
                    Configuration.UserID = userId;
                    Configuration.SynchStatus = SynchStatus.UserIDObtained;
                    log.Info("User id obtained and saved. Synching finished.");
                    return;
                
                case MessageType.ALREADY_SYNCHED:
                    log.WarnFormat("Already entangled with key: '{0}'. Proceeding with obtained user id.", pSynchKey);
                    userId = int.Parse(rArray[1]);
                    Configuration.UserID = userId;
                    Configuration.SynchStatus = SynchStatus.UserIDObtained;
                    log.Info("User id obtained and saved. Synching finished.");
                    return;

                case MessageType.ENTANGLEMENT_FULL:
                    log.WarnFormat("Entanglement for key: '{0}' is already full.", pSynchKey);
                    throw new ArgumentException(String.Format("SynchKey: '{0}' is already used. Please use different one."),rArray[1]);

                case MessageType.ARGUMENT_NULL:
                    log.ErrorFormat("Server returned error: argument is null ({0})",rArray[1]);
                    throw new ArgumentNullException(String.Format("Argument '{0}' was not provided.", rArray[1]));

                case MessageType.SERV_DATA_CORRUPTED:
                    log.ErrorFormat("Server returned data corruption error: {0}", rArray[1]);
                    throw new Exception(String.Format("Error occured. Please try again or synch with different key. ({0})", rArray[1]));

                case MessageType.SERV_TECH_ERROR:
                    log.ErrorFormat("Server returned technical error: {0}", rArray[1]);
                    throw new Exception(String.Format("Error occured. Please try again or synch with different key. ({0})", rArray[1]));

                default:
                    throw new NotImplementedException("Unrecognised server message. Server failure or application is out-of-date. Recived message:"+result);
            }
        }

        [Obsolete("Created new synch metod that uses ServerConnector")]
        public bool Synch(string pSynchKey)
        {
            Cryptography crypt = Cryptography.GetInstance();
            string publicKey = crypt.GetPublicKeyXML();
            
            WebRequest webRequest = WebRequest.Create(uri);
            if (Properties.Settings.Default.UseProxy)
            {
                webRequest.Proxy = WebRequest.DefaultWebProxy;
                webRequest.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
            }
            webRequest.Method = WebRequestMethods.Http.Post;
            webRequest.ContentType = "application/x-www-form-urlencoded";

            string postData = "synchKey=" + HttpUtility.UrlEncode(pSynchKey) +
                                "&publicKey="+HttpUtility.UrlEncode(publicKey);
            byte[] postBytes = Encoding.ASCII.GetBytes(postData);

            // --- Post ---
            Stream os = null;
            try
            {
                webRequest.ContentLength = postBytes.Length;
                os = webRequest.GetRequestStream();
                os.Write(postBytes, 0, postBytes.Length);
            }
            catch (WebException ex)
            {
                log.Error("Exception while making POST request:" + webRequest.ToString(), ex);
                return false;
            }
            finally
            {
                if (os != null)
                    os.Close();
            }

            // --- Response --- 
            string response;
            try
            {
                WebResponse webResponse = webRequest.GetResponse();
                if (webResponse == null)
                    throw new WebException("Did not get response from synch server.");

                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
                response = sr.ReadToEnd().Trim();
            }
            catch (WebException ex)
            {
                log.Error("Exception while getting response from synch server", ex);
                return false;
            }

            // --- Check/Parse response ---
            int UserID;
            try
            {
                UserID = int.Parse(response);
            }
            catch (Exception e)
            {
                log.Error("Error parsing response into integer id", e);
                return false;
            }

            // --- Store UserID --
            Configuration.UserID = UserID;


            Configuration.SynchStatus = SynchStatus.UserIDObtained;
            return true;
        }
    }
}
